﻿using System;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using NETCONLib;
using WirelessAccessPoint.Core;
using WirelessAccessPoint.Model;

namespace WirelessAccessPoint.Services
{
    /// <summary>
    /// Internet Connection Sharing (ICS)を処理するサービスです。
    /// </summary>
    public class NetSharingService
    {
        #region Service

        /// <summary>
        /// Internet Connection Sharing (ICS)の状態を取得します。
        /// </summary>
        /// <param name="selectedPublicNetSharing">
        /// 選択されているPublic側のInternet Connection Sharing (ICS)。
        /// </param>
        /// <returns>
        /// Internet Connection Sharing (ICS)の状態。
        /// </returns>
        public NetSharingContext Update(NetSharing selectedPublicNetSharing)
        {
            var context = new NetSharingContext();
            context.SelectedPublicNetSharing = selectedPublicNetSharing;
            NetSharingManager manager = null;
            INetSharingEveryConnectionCollection collection = null;

            try
            {
                manager = new NetSharingManager();
                collection = manager.EnumEveryConnection;

                foreach (INetConnection connection in collection)
                {
                    INetConnectionProps property = null;
                    INetSharingConfiguration configuration = null;

                    try
                    {
                        property = manager.get_NetConnectionProps(connection);
                        configuration = manager.get_INetSharingConfigurationForINetConnection(connection);
                        var netSharing = new NetSharing()
                        {
                            GUID = property.Guid,
                            Name = property.Name,
                            DeviceName = property.DeviceName,
                            Characteristics = property.Characteristics,
                            Status = property.Status,
                            MediaType = property.MediaType,
                            SharingEnabled = configuration.SharingEnabled,
                            SharingConnectionType = configuration.SharingConnectionType,
                            IPAddresses = NetworkInterface.GetAllNetworkInterfaces()
                                .Where(n => n.Id == property.Guid)
                                .SelectMany(n => n.GetIPProperties().UnicastAddresses
                                .Select(u => u.Address).Where(a => a.AddressFamily == AddressFamily.InterNetwork))
                                .ToArray()
                        };

                        if (configuration.SharingEnabled)
                        {
                            if (configuration.SharingConnectionType == tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PRIVATE)
                            {
                                context.ActivePrivateNetSharing = netSharing;
                            }

                            if (configuration.SharingConnectionType == tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PUBLIC)
                            {
                                context.ActivePublicNetSharing = netSharing;
                                context.SelectedPublicNetSharing = netSharing;
                            }
                        }

                        context.NetSharings.Add(netSharing);
                    }
                    finally
                    {
                        configuration.ReleaseComObject();
                        property.ReleaseComObject();
                        connection.ReleaseComObject();
                    }
                }
            }
            finally
            {
                collection.ReleaseComObject();
                manager.ReleaseComObject();
            }

            return context;
        }

        /// <summary>
        /// Internet Connection Sharing (ICS)を開始します。
        /// </summary>
        /// <param name="activeHostedNetwork">
        /// 開始しているHosted Network。
        /// </param>
        /// <param name="selectedPublicNetSharing">
        /// 選択されているPublic側のInternet Connection Sharing (ICS)。
        /// </param>
        public void Enable(HostedNetwork activeHostedNetwork, NetSharing selectedPublicNetSharing)
        {
            NetSharingManager manager = null;
            INetSharingEveryConnectionCollection collection = null;

            try
            {
                manager = new NetSharingManager();
                collection = manager.EnumEveryConnection;

                foreach (INetConnection connection in collection)
                {
                    INetConnectionProps property = null;
                    INetSharingConfiguration configuration = null;

                    try
                    {
                        property = manager.get_NetConnectionProps(connection);
                        configuration = manager.get_INetSharingConfigurationForINetConnection(connection);

                        if (activeHostedNetwork.DeviceID == Guid.Parse(property.Guid))
                        {
                            configuration.EnableSharing(tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PRIVATE);
                        }
                        
                        if (selectedPublicNetSharing.GUID == property.Guid)
                        {
                            configuration.EnableSharing(tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PUBLIC);
                        }
                    }
                    finally
                    {
                        configuration.ReleaseComObject();
                        property.ReleaseComObject();
                        connection.ReleaseComObject();
                    }
                }
            }
            finally
            {
                collection.ReleaseComObject();
                manager.ReleaseComObject();
            }
        }

        /// <summary>
        /// Internet Connection Sharing (ICS)を停止します。
        /// </summary>
        public void Disable()
        {
            NetSharingManager manager = null;
            INetSharingEveryConnectionCollection collection = null;

            try
            {
                manager = new NetSharingManager();
                collection = manager.EnumEveryConnection;

                foreach (INetConnection connection in collection)
                {
                    INetConnectionProps property = null;
                    INetSharingConfiguration configuration = null;

                    try
                    {
                        property = manager.get_NetConnectionProps(connection);
                        configuration = manager.get_INetSharingConfigurationForINetConnection(connection);
                        configuration.DisableSharing();
                    }
                    finally
                    {
                        configuration.ReleaseComObject();
                        property.ReleaseComObject();
                        connection.ReleaseComObject();
                    }
                }
            }
            finally
            {
                collection.ReleaseComObject();
                manager.ReleaseComObject();
            }
        }

        #endregion
    }
}
